package gu.sql2java;

import java.util.Map;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import com.google.common.base.Throwables;

import static com.google.common.base.MoreObjects.firstNonNull;

/**
 * converter between {@link BaseBean} class and {@link Map} class
 * @author guyadong
 *
 * @param <L> BaseBean class
 * @param <R> Map class
 */
@SuppressWarnings("rawtypes")
public class MapConverter <L extends BaseBean,R extends Map> extends IBeanConverter.AbstractHandle<L, R> implements Constant{
	private final RowMetaData metaData;
	private final boolean nullAsUninitialzied;
	public MapConverter(Class<L> leftClass, Class<R> rightClass,boolean nullAsUninitialzied) {
		super(leftClass, rightClass);
		this.metaData = RowMetaData.getMetaData(leftClass);
		this.nullAsUninitialzied = nullAsUninitialzied;
	}
	public MapConverter(Class<L> leftClass, Class<R> rightClass) {
		this(leftClass, rightClass,true);
	}

	@Override
	protected void doFromRight(L left, R right) {
		try{
			for(int columnId = 0; columnId < metaData.columnCount; ++columnId){
				String columnName = metaData.columnJavaNameOf(columnId);
				if(right.containsKey(columnName)){
					Object value = right.get(columnName);
					if(null != value || !nullAsUninitialzied){
						left.setValue(columnId, cast(metaData.columnTypeOf(columnId),value));	
					}
				}
			}
			left.setNew(firstNonNull((Boolean)right.get(FIELD_NEW), true));
			Integer modified = (Integer) right.get(FIELD_MODIFIED);
			Integer initialized = (Integer) right.get(FIELD_INITIALIZED);
			if(null != initialized){
				left.setInitialized(initialized);
			}
			if(null != modified){
				left.setModified(modified);
			}
		}catch(Exception e){
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void doToRight(L left, R right) {
		try{
			for(int columnId = 0; columnId < metaData.columnCount; ++columnId){
				if(left.isInitialized(columnId)){
					right.put(metaData.columnJavaNameOf(columnId), left.getValueChecked(columnId));
				}
			}
			right.put(FIELD_NEW, left.isNew());
			right.put(FIELD_INITIALIZED, left.getInitialized());
			right.put(FIELD_MODIFIED, left.getModified());
		}catch(Exception e){
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}
	private static Object cast(Class<?> clazz,Object value){
		return TypeUtils.cast(value, clazz, ParserConfig.global);
	}
}
